package com.wenbing.miio.core;

import com.wenbing.miio.core.exception.NetworkLayerException;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * 多子协议分发适配层
 * @author wen bing
 * @projectName: miio
 * @package: com.wenbing.miio.core
 * @className: DisLayer
 * @date 2024/09/23 22:17
 **/
public abstract class StacksAdapterNetworkLayer extends AbstractNetworkLayer implements Bootable {

    /**
     * 子协议栈列表
     */
    private List<NetworkStackLayer> list;

    protected StacksAdapterNetworkLayer() {
        this(false);
    }

    protected StacksAdapterNetworkLayer(boolean multiMatch) {
        this(8);
    }

    protected StacksAdapterNetworkLayer(int initialCapacity) {
        this.list = new ArrayList<>(initialCapacity);
    }

    @Override
    protected abstract void inboundContextCopy(NetworkLayerContext from, NetworkLayerContext to);

    @Override
    protected abstract void outboundContextCopy(NetworkLayerContext from, NetworkLayerContext to);

    /**
     * 注册子协议栈
     * @param layer
     */
    public void registerChildNetworkStackLayer(NetworkStackLayer layer) {
        assert layer != null;
        /*NetworkStack.NetworkLayerNode node = layer.getNetworkLayerNode();
        // 处于同一逻辑层，其上层节点应为本节点的上层节点
        node.setUpperLayerNode(this.getNetworkLayerNode().getUpperLayerNode());
        node.setNetworkStack(()-> {
             return getNetworkLayerNode().getNetworkStack().get();
        });*/
        list.add(layer);
    }

    @Override
    public void boot() {
        for (NetworkStackLayer layer : list) {
            // 处于同一逻辑层，其上层节点应为本节点的上层节点
            layer.getNetworkLayerNode().setUpperLayerNode(getNetworkLayerNode().getUpperLayerNode());
            layer.getNetworkLayerNode().setNetworkStack(getNetworkLayerNode().getNetworkStack());
            LOGGER.info("{} load layer {} success", this, layer);
        }
    }

    @Override
    protected void deliverUpperLayer(NetworkLayerContext context, ByteBuffer packingData) throws NetworkLayerException, IOException {
        for (NetworkStackLayer layer : list) {
            packingData.position(0);
            if (layer.outboundCondition(context, packingData) ) {
                LOGGER.info("deliver to the next layer");
                layer.outbound(context, packingData);
                return;
            }
        }
    }

    @Override
    protected void deliverLowerLayer(NetworkLayerContext context, ByteBuffer packingData) throws NetworkLayerException, IOException {
        for (NetworkStackLayer layer : list) {
            packingData.position(0);
            if (layer.inboundCondition(context, packingData) ) {
                LOGGER.info("deliver to the next layer");
                layer.inbound(context, packingData);
                return;
            }
        }
    }

}
